﻿#pragma once
// Inner Fire 游戏引擎库
// 模糊类
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 用于模糊的工具类。根据《DirectX12游戏开发实战》中的工具类修改。
// 原作者：Frank Luna
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-26

#include <dx_core/dx_core.h>
#include <vector>

namespace ifire {

class BlurFilter {
public:
  ///< summary>
  /// 因为离屏的纹理需要和屏幕区域一样，所以每次Resize之后都需要重新构建。
  ///</summary>
  BlurFilter(ID3D12Device* device, UINT width, UINT height, DXGI_FORMAT format);
  BlurFilter(const BlurFilter& rhs) = delete;
  BlurFilter& operator=(const BlurFilter& rhs) = delete;
  ~BlurFilter() = default;

  // 得到输出项目
  ID3D12Resource* Output();

  // 将已经产生的Output项目输出到后备缓冲区，并且将后备缓冲区的项目复元
  void Restore(ID3D12GraphicsCommandList* cmd, ID3D12Resource* back_buffer);

  // 用于创建描述符堆。这个用于追加到其它纹理后面。
  void BuildDescriptors(CD3DX12_CPU_DESCRIPTOR_HANDLE hCpuDescriptor,
      CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuDescriptor, UINT descriptorSize);

  // 重新构建离屏纹理
  void OnResize(UINT newWidth, UINT newHeight);

  ///< summary>
  /// 主计算。对纹理进行blur_count次模糊.
  ///</summary>
  void Execute(ID3D12GraphicsCommandList* cmd,
    ID3D12RootSignature* root_sig, ID3D12PipelineState* horz_blur_pso,
    ID3D12PipelineState* vert_blur_pso, ID3D12Resource* input, int blur_count);

private:
  std::vector<float> CalcGaussWeights(float sigma);

  void BuildDescriptors();
  void BuildResources();

private:
  const int MAX_BLUR_RADIUS = 5;

  ID3D12Device* device_ = nullptr;

  UINT width_ = 0;
  UINT height_ = 0;
  DXGI_FORMAT format_ = DXGI_FORMAT_R8G8B8A8_UNORM;

  // 这个就是需要进行“倒腾”的描述符。
  CD3DX12_CPU_DESCRIPTOR_HANDLE blur_0_cpu_srv_;
  CD3DX12_CPU_DESCRIPTOR_HANDLE blur_0_cpu_uav_;
  CD3DX12_CPU_DESCRIPTOR_HANDLE blur_1_cpu_srv_;
  CD3DX12_CPU_DESCRIPTOR_HANDLE blur_1_cpu_uav_;
  CD3DX12_GPU_DESCRIPTOR_HANDLE blur_0_gpu_srv_;
  CD3DX12_GPU_DESCRIPTOR_HANDLE blur_0_gpu_uav_;
  CD3DX12_GPU_DESCRIPTOR_HANDLE blur_1_gpu_srv_;
  CD3DX12_GPU_DESCRIPTOR_HANDLE blur_1_gpu_uav_;

  // Two for ping-ponging the textures.
  Microsoft::WRL::ComPtr<ID3D12Resource> blur_map_0_ = nullptr;
  Microsoft::WRL::ComPtr<ID3D12Resource> blur_map_1_ = nullptr;
};
} // namespace ifire
